from datetime import datetime
from typing import Optional
from pydantic import BaseModel
from bson import ObjectId

class PyObjectId(ObjectId):
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        if not ObjectId.is_valid(v):
            raise ValueError("Invalid objectid")
        return ObjectId(v)

    @classmethod
    def __modify_schema__(cls, field_schema):
        field_schema.update(type="string")

class WalletBase(BaseModel):
    user_id: PyObjectId
    balance: float

class WalletCreate(WalletBase):
    pass

class WalletUpdate(BaseModel):
    balance: Optional[float] = None

class WalletInDBBase(WalletBase):
    id: PyObjectId
    created_at: datetime
    updated_at: datetime

    class Config:
        arbitrary_types_allowed = True
        json_encoders = {ObjectId: str}

class Wallet(WalletInDBBase):
    pass

class WalletInDB(WalletInDBBase):
    pass

class RedPacketBase(BaseModel):
    sender_id: PyObjectId
    receiver_id: PyObjectId
    amount: float
    status: str  # 'sent', 'claimed', 'expired'

class RedPacketCreate(RedPacketBase):
    pass

class RedPacketUpdate(BaseModel):
    status: Optional[str] = None
    claimed_at: Optional[datetime] = None

class RedPacketInDBBase(RedPacketBase):
    id: PyObjectId
    created_at: datetime

    class Config:
        arbitrary_types_allowed = True
        json_encoders = {ObjectId: str}

class RedPacket(RedPacketInDBBase):
    claimed_at: Optional[datetime] = None

class RedPacketInDB(RedPacketInDBBase):
    claimed_at: Optional[datetime] = None

class TransactionBase(BaseModel):
    user_id: PyObjectId
    type: str  # 'recharge', 'withdraw', 'send_red_packet', 'claim_red_packet', 'transfer_out', 'transfer_in'
    amount: float
    balance_after: float
    description: str

class TransactionCreate(TransactionBase):
    pass

class TransactionUpdate(BaseModel):
    pass

class TransactionInDBBase(TransactionBase):
    id: PyObjectId
    related_id: Optional[PyObjectId] = None
    created_at: datetime

    class Config:
        arbitrary_types_allowed = True
        json_encoders = {ObjectId: str}

class Transaction(TransactionInDBBase):
    pass

class TransactionInDB(TransactionInDBBase):
    pass